use super::{Key, Node};
use std::convert::From;
use std::{error::Error, fmt, rc::Rc};

pub enum XErr {
    NotExists,
    AlreadyExists,
    Unknown,
}

impl fmt::Display for XErr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            XErr::NotExists => write!(f, "Not Exists!"),
            XErr::AlreadyExists => write!(f, "Key/Value Already Exists!"),
            XErr::Unknown => write!(f, "Unknown Error!"),
        }
    }
}

impl fmt::Debug for XErr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self, f)
    }
}

impl Error for XErr {
    fn description(&self) -> &str {
        match self {
            XErr::NotExists => "Not Exists!",
            XErr::AlreadyExists => "Key/Value Already Exists!",
            XErr::Unknown => "Unknown Error!",
        }
    }

    fn source(&self) -> Option<&(dyn Error + 'static)> {
        None
    }
}

pub enum ZErr<K: Key, V> {
    NotExists(Option<Rc<Node<K, V>>>),
    AlreadyExists(Rc<Node<K, V>>),
    Unknown,
}

impl<K: Key, V> fmt::Display for ZErr<K, V> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            ZErr::NotExists(_) => write!(f, "Not Exists!"),
            ZErr::AlreadyExists(_) => write!(f, "Key/Value Already Exists!"),
            ZErr::Unknown => write!(f, "Unknown Error!"),
        }
    }
}

impl<K: Key, V> fmt::Debug for ZErr<K, V> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self, f)
    }
}

impl<K: Key, V> Error for ZErr<K, V> {
    fn description(&self) -> &str {
        match self {
            ZErr::NotExists(_) => "Not Exists!",
            ZErr::AlreadyExists(_) => "Key/Value Already Exists!",
            ZErr::Unknown => "Unknown Error!",
        }
    }

    fn source(&self) -> Option<&(dyn Error + 'static)> {
        None
    }
}

impl<K: Key, V> From<ZErr<K, V>> for XErr {
    fn from(error: ZErr<K, V>) -> Self {
        match error {
            ZErr::NotExists(_) => XErr::NotExists,
            ZErr::AlreadyExists(_) => XErr::AlreadyExists,
            ZErr::Unknown => XErr::Unknown,
        }
    }
}
